﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Channels;
using System.Xml;
using System.ServiceModel;

namespace WcfContrib.Helpers
{
    /// <summary>
    /// A helper class for dealing with bindings
    /// </summary>
    public static class BindingHelper
    {
        #region Boosting
        /// <summary>
        /// Tries boosting the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// Returns whether the boosting had been applied. (Supports only known bindings, not custom)
        /// </summary>
        /// <param name="binding">The binding.</param>
        /// <returns>Whether the boosting had taken place or not.</returns>
        public static bool TryBoosting(this Binding binding)
        {
            if (!TryBindingAction<NetTcpBinding>(binding, b => b.BoostBinding()))
                if (!TryBindingAction<BasicHttpBinding>(binding, b => b.BoostBinding()))
                    if (!TryBindingAction<WSHttpBinding>(binding, b => b.BoostBinding()))
                        if (!TryBindingAction<NetNamedPipeBinding>(binding, b => b.BoostBinding()))
                            if (!TryBindingAction<NetMsmqBinding>(binding, b => b.BoostBinding()))
                                if (!TryBindingAction<WebHttpBinding>(binding, b => b.BoostBinding()))
                                    return false;

            return true;
        }

        /// <summary>
        /// Boosts the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public static void BoostBinding(this NetTcpBinding binding)
        {
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferPoolSize = int.MaxValue;
            binding.MaxBufferSize = int.MaxValue;
            binding.ReaderQuotas = GetBoostedReaderQuotas();
        }

        /// <summary>
        /// Boosts the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public static void BoostBinding(this NetMsmqBinding binding)
        {
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferPoolSize = int.MaxValue;
            binding.ReaderQuotas = GetBoostedReaderQuotas();
        }

        /// <summary>
        /// Boosts the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public static void BoostBinding(this BasicHttpBinding binding)
        {
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferPoolSize = int.MaxValue;
            binding.MaxBufferSize = int.MaxValue;
            binding.ReaderQuotas = GetBoostedReaderQuotas();
        }

        /// <summary>
        /// Boosts the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public static void BoostBinding(this WSHttpBinding binding)
        {
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferPoolSize = int.MaxValue;
            binding.ReaderQuotas = GetBoostedReaderQuotas();
        }

        /// <summary>
        /// Boosts the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public static void BoostBinding(this NetNamedPipeBinding binding)
        {
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferPoolSize = int.MaxValue;
            binding.MaxBufferSize = int.MaxValue;
            binding.ReaderQuotas = GetBoostedReaderQuotas();
        }

        /// <summary>
        /// Boosts the binding configuration.
        /// Increases the max received message size, the buffer sizes and the reader quotas.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public static void BoostBinding(this WebHttpBinding binding)
        {
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferPoolSize = int.MaxValue;
            binding.MaxBufferSize = int.MaxValue;
            binding.ReaderQuotas = GetBoostedReaderQuotas();
        }

        internal static XmlDictionaryReaderQuotas GetBoostedReaderQuotas()
        {
            return new XmlDictionaryReaderQuotas().SetReaderQuotasValues(int.MaxValue);
        }

        internal static XmlDictionaryReaderQuotas SetReaderQuotasValues(this XmlDictionaryReaderQuotas quotas, int value)
        {
            quotas.MaxArrayLength = value;
            quotas.MaxBytesPerRead = value;
            quotas.MaxDepth = value;
            quotas.MaxNameTableCharCount = value;
            quotas.MaxStringContentLength = value;

            return quotas;
        }
        #endregion

        /// <summary>
        /// Tries an action on a binding if a cast had been successfuly.
        /// Returnes whether the action had been executed.
        /// </summary>
        /// <typeparam name="T">The binding assignable type</typeparam>
        /// <param name="binding">The binding.</param>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        public static bool TryBindingAction<T>(this Binding binding, Action<T> action)
            where T : Binding
        {
            T obj = binding as T;
            if (obj != null)
            {
                action(obj);
                return true;
            }

            return false;
        }
    }
}
